package services

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"server/global"
	"server/utils/tools"
	"strconv"
	"strings"
	"time"
)

// GetPagingList 带分页列表
func GetPagingList[T any](Db *gorm.DB, data T, c *gin.Context, args ...string) ([]T, int64) {
	Db = Query(Db, c)  //查询构造
	Db = Paging(Db, c) //分页

	//快速搜索
	quickSearch := c.Query("quickSearch")
	if quickSearch != "" && len(args) >= 1 {
		Db = Db.Where(args[0]+" like ?", "%"+quickSearch+"%")
	}

	if len(args) >= 2 {
		Db = Db.Preload(args[1])
	}

	var list []T
	var total int64
	Db.Model(&data).
		Find(&list).Offset(-1).Count(&total)

	return list, total
}

// GetById 单条
func GetById[T any](id any, data T) T {
	Db := global.GL_DB

	Db.Model(&data).
		Where("id =?", id).First(&data)
	return data

}

// Create 新增
func Create[T any](data T) (T, error) {
	Db := global.GL_DB
	err := Db.Transaction(func(tx *gorm.DB) error {
		//创建
		if err := tx.Create(&data).Error; err != nil {
			// 返回任何错误都会回滚事务
			return err
		}

		// 返回 nil 提交事务
		return nil
	})

	return data, err
}

// Update 编辑
func Update[T any](data T) error {
	Db := global.GL_DB

	return Db.Updates(&data).Error

}

// Delete 删除
func Delete[T any](ids []int, data T) error {
	Db := global.GL_DB
	return Db.Delete(&data, ids).Error

}

// Query 查询构造
func Query(db *gorm.DB, c *gin.Context) *gorm.DB {
	search := c.QueryArray("search[]")

	for _, v := range search {
		//json转map
		maps := make(map[string]interface{})
		json.Unmarshal([]byte(v), &maps)
		var field string
		if maps["tableName"] != nil {
			field = maps["tableName"].(string) + "." + maps["field"].(string)
		} else {
			field = maps["field"].(string)
		}

		val, _ := tools.CheckType(maps["val"])

		operator := maps["operator"].(string)
		if operator == "eq" {
			operator = "="
		} else if operator == "ne" {
			operator = "!="
		} else if operator == "gt" {
			operator = ">"
		} else if operator == "egt" {
			operator = ">="
		} else if operator == "lt" {
			operator = "<"
		} else if operator == "elt" {
			operator = "<="
		}

		if field != "" && val != "" {
			switch operator {
			case "LIKE":
				db = db.Where(field+" LIKE ?", "%"+val+"%")
			case "RANGE":
				arr := strings.Split(val, ",")
				if maps["render"] == "datetime" {
					loc, _ := time.LoadLocation("Local")
					startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", arr[0], loc)
					endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", arr[1], loc)
					db = db.Where(field+" between ? and ?", startTime.Unix(), endTime.Unix())
				} else {
					db = db.Where(field+" between ? and ?", arr[0], arr[1])
				}

			case "FIND_IN_SET":
				db = db.Where("find_in_set(?,"+field+")", val)
			case "TEXT_ARR":
				vals := strings.Split(val, "\n")
				db = db.Where(field+" in ?", vals)

			//case "REGEXP":
			//	val = getDepartmentIds(val, 0)
			//	val = strings.Replace(val, ",", "|", -1)
			//	db = db.Where("CONCAT (','," + field + ",',') REGEXP ',(" + val + "),'")

			default:
				db = db.Where(field+" "+operator+" ?", val)
			}

		}

	}

	order := c.Query("order")
	if order == "" {
		db = db.Order("id desc")
	} else {
		arr := strings.Split(order, ",")
		db = db.Order(arr[0] + " " + arr[1])
	}

	return db
}

// Paging 分页
func Paging(db *gorm.DB, c *gin.Context) *gorm.DB {
	page, _ := strconv.Atoi(c.Query("page"))
	pageTotal, _ := strconv.Atoi(c.Query("limit"))
	if page == 0 {
		page = 1
	}
	if pageTotal == 0 {
		pageTotal = 10
	}
	db = db.Limit(pageTotal).Offset((page - 1) * pageTotal)

	return db
}

// GetSelect 远程下拉
func GetSelect[T any](data T, c *gin.Context, search ...string) []T {
	Db := global.GL_DB

	//快速搜索
	quickSearch := c.Query("quickSearch")
	if quickSearch != "" && len(search) > 0 {
		Db = Db.Where(search[0]+" like ?", "%"+quickSearch+"%")
	}
	var list []T
	Db.Model(&data).Find(&list)

	return list
}

// GetDbSelect 远程下拉 带Db
func GetDbSelect[T any](Db *gorm.DB, data T, c *gin.Context, search ...string) []T {

	//快速搜索
	quickSearch := c.Query("quickSearch")
	if quickSearch != "" && len(search) > 0 {
		Db = Db.Where(search[0]+" like ?", "%"+quickSearch+"%")
	}
	var list []T
	Db.Model(&data).Find(&list)

	return list
}
